package com.authine.cloudpivot.web.api.controller.common;

import com.aliyun.oss.OSS;
import com.aliyun.oss.model.OSSObject;
import com.authine.cloudpivot.engine.api.model.organization.UserModel;
import com.authine.cloudpivot.engine.api.model.runtime.AttachmentModel;
import com.authine.cloudpivot.engine.enums.type.FileUploadType;
import com.authine.cloudpivot.web.api.controller.base.PermissionController;
import com.authine.cloudpivot.web.api.exception.PortalException;
import com.authine.cloudpivot.web.api.exception.ResultEnum;
import com.authine.cloudpivot.web.api.handler.CustomizedOrigin;
import com.authine.cloudpivot.web.api.oss.FileStorageConfiguration;
import com.authine.cloudpivot.web.api.oss.OSSClient;
import com.authine.cloudpivot.web.api.sftp.SFTPClient;
import com.authine.cloudpivot.web.api.util.ImageUtil;
import com.authine.cloudpivot.web.api.util.ImageUtils;
import com.authine.cloudpivot.web.api.view.ResponseResult;
import com.authine.cloudpivot.web.api.view.system.FontTextVO;
import com.authine.cloudpivot.web.api.view.system.OssConfigVO;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifDirectoryBase;
import com.drew.metadata.exif.ExifIFD0Directory;
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.zip.Adler32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Api(tags = "公共服务::文件上传下载")
@Controller
@RequestMapping("/api/aliyun")
@Slf4j
@CustomizedOrigin(level = 1)
public class OSSExtController extends PermissionController {

    public static final String STORAGE_METHOD_OSS = "oss";
    public static final String KEY_WORKFLOW_ATTACHMENT = "cloudpivot:fileupload:workflow_attachment";
    private static final String MIMETYPE_SUFFIX = "application/";
    private static final String IMAGE_SUFFIX = "image/";
    private static final String PIC_EXTENSION = ".jpg.JPG.png.PNG.jpeg.JPEG";
    /**
     * 文件上传黑名单。为保证安全，只要文件名中包含该黑名单内容即不允许上传
     */
    private static final String[] IGNORE_FILE_TYPES = {
            ".php", ".php5", ".php4", ".php3", ".php2", ".php1",
            ".html", ".htm", ".phtml", ".pHp", ".pHp5", ".pHp4", ".pHp3", ".pHp2", ".pHp1",
            ".Html", ".Htm", ".pHtml", ".jsp", ".jspa", ".jspx", ".jsw", ".jsv", ".jspf", ".jtml", ".jSp",
            ".jSpx", ".jSpa", ".jSw", ".jSv", ".jSpf", ".jHtml", ".asp", ".aspx", ".asa", ".asax",
            ".ascx", ".ashx", ".asmx", ".cer", ".aSp", ".aSpx", ".aSa", ".aSax", ".aScx", ".aShx", ".aSmx", ".cEr", ".sWf", ".swf",".lvenc"};
    /**
     * 系统默认允许的上传文件类型
     */
    private static List<String> FILE_TYPE_WHITE_LIST = Arrays.asList(
            ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".svg", ".tif",
            ".docx", ".xlsx", ".pptx", ".doc", ".xls", ".ppt", ".wpt", ".dot", ".rtf", ".txt", ".xml", ".pdf",
            ".rar", ".zip",
            ".MP3", ".WMA", ".WAV", ".MIDI", ".CDA", ".AVI", ".mov", ".rmvb", ".rm", ".FLV", ".mp4", ".3GP"
    );
    @Autowired
    private OSSClient ossClient;
    @Autowired
    private SFTPClient sftpClient;
    @Autowired
    private RedisTemplate<String, AttachmentModel> redisTemplate;
    /**
     * 用户扩展允许上传文件类型,配置使用英文逗号分隔形式：.ext1,.ext2
     */
    @Value("${cloudpivot.attachment.fileTypes:}")
    private String extendFileTypes;

    public static String[] getFileInfo(String fileName) {
        int index = fileName.lastIndexOf(".");
        String toPrefix = "";
        String toSuffix = "";
        if (index == -1) {
            toPrefix = fileName;
        } else {
            toPrefix = fileName.substring(0, index);
            toSuffix = fileName.substring(index, fileName.length());
        }
        return new String[]{toPrefix, toSuffix};
    }

    @PostConstruct
    public void init() {
        if (StringUtils.isNotEmpty(extendFileTypes)) {
            String[] split = extendFileTypes.split(",");
            ArrayList<String> whiteList = Lists.newArrayList();
            whiteList.addAll(Arrays.asList(split));
            whiteList.addAll(FILE_TYPE_WHITE_LIST);
            FILE_TYPE_WHITE_LIST = whiteList;
        }
    }

    @PostMapping(value = "/upload")
    @ResponseBody
    @ApiOperation(value = "oss 文件上传接口,注意：key 用 file")
    public ResponseResult<AttachmentModel> upload(
            @RequestParam MultipartFile file, Boolean isAddWatermark, String locationInfo, String fileName, Boolean isRichText, Boolean rewriteFilename) throws Exception {
        log.info("fileOriginalName:{},fileName:{}", file.getOriginalFilename(), fileName);
        if (StringUtils.isEmpty(fileName)) {
            fileName = file.getOriginalFilename();
            //上传文件重新命名
            if(rewriteFilename!=null  && rewriteFilename){
                fileName = fileName.trim();
                String tempSuffix = fileName.substring(fileName.lastIndexOf('.'));
                fileName =  UUID.randomUUID().toString().replace("-", "") + tempSuffix;
            }
        }
        fileName = fileName.trim();
        //检查上传文件类型
//        checkFileType(fileName);
        String fileNameTemplate = null;
        try {
            if (!Strings.isNullOrEmpty(fileName)) {
                log.debug(fileName);
                String suffix = fileName.substring(fileName.lastIndexOf('.') + 1);

                String refId = UUID.randomUUID().toString().replace("-", "");
                fileNameTemplate = refId.concat(fileName);

                byte[] targetBytes = null;
                Boolean isPic = checkImageFile(file);
                if (log.isDebugEnabled()) {
                    log.debug(
                            "isPic = {}, isAddWatermark = {}, locationInfo = {}",
                            isPic,
                            isAddWatermark,
                            locationInfo);
                }
                if (isPic && isAddWatermark != null && isAddWatermark) {
                    int orientation = 0;
                    try {
                        Metadata metadata = ImageMetadataReader.readMetadata(new ByteArrayInputStream(file.getBytes()));
                        Directory directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
                        if (directory != null && directory.containsTag(ExifDirectoryBase.TAG_ORIENTATION)) {
                            orientation = directory.getInt(ExifDirectoryBase.TAG_ORIENTATION);
                            log.debug("图片方向为: {}", orientation);
                        }
                    } catch (Exception e) {
                        //do nothing
                    }

                    // 如果是图片，则根据配置加上水印
                    String userId = getUserId();
                    UserModel user = getOrganizationFacade().getUser(userId);
                    String userName = (user == null ? "" : user.getName());
                    LocalDateTime now = LocalDateTime.now();
                    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    if (StringUtils.isNotEmpty(locationInfo) && locationInfo.length() > 40) {
                        // 支持最多40个字，超过的…表示
                        locationInfo = locationInfo.substring(0, 40) + "...";
                    }
                    targetBytes =
                            ImageUtils.drawTextInImg(
                                    file.getBytes(),
                                    new FontTextVO(
                                            Lists.newArrayList(
                                                    now.format(dateTimeFormatter) + " " + userName, locationInfo),
                                            9,
                                            "#FFFFFF",
                                            24,
                                            "SimHei",
                                            0d,
                                            0.64f), orientation);
                    if (log.isDebugEnabled()) {
                        log.debug("drawTextInImg is finished....");
                    }
                }
//                Base64ImageStr该字段暂时没有用上，不需要进行压缩和写入
//                String smallimageBase64 = "";
//                if (isPic) {
//
//                    BufferedImage image = null;
//                    if (Objects.nonNull(targetBytes)) {
//                        image = ImageIO.read(new ByteArrayInputStream(targetBytes));
//                    } else {
//                        image = ImageIO.read(file.getInputStream());
//                    }
//                    log.info("<----------转换图片结束---------->");
//                    log.info("<----------压缩图片开始---------->");
//                    BufferedImage smallImage = ImageUtil.resizeImage(image, 5);
//                    smallimageBase64 = ImageUtil.imageThumbnailsToBase64(smallImage, fileName);
//                    log.info("<----------压缩图片结束---------->");
//                }
                if (FileStorageConfiguration.getFileUploadType() == FileUploadType.OSS) {
                    log.debug("the upload type is sso");
                    File newFile = new File(fileNameTemplate);
                    FileOutputStream os = FileUtils.openOutputStream(newFile);
                    if (isPic && isAddWatermark != null && isAddWatermark) {
                        os.write(targetBytes);
                    } else {
                        os.write(file.getBytes());
                    }
                    os.close();
//                    file.transferTo(newFile);
                    // 上传到OSS
                    ossClient.fileUpload(refId, newFile);
                    newFile.delete();
                } else {
                    log.info("the upload type is sftp");
                    try {
                        if (targetBytes == null) {
                            targetBytes = file.getBytes();
                        }
                        sftpClient.uploadFile(fileNameTemplate, new ByteArrayInputStream(targetBytes));
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                        throw e;
                    }
                }

                // {"refId":"xxx","name":"filename","fileSize":10000,"fileExtension":".pdf","mimeType":"application/pdf","storageMethod":"oss"}
                AttachmentModel resourceModel = new AttachmentModel();
                resourceModel.setRefId(refId);
                resourceModel.setName(fileName);
                resourceModel.setFileExtension(".".concat(suffix));
                resourceModel.setFileSize(new Long(file.getSize()).intValue());
//                resourceModel.setBase64ImageStr(smallimageBase64);
                if (PIC_EXTENSION.contains(suffix)) {
                    //IE图片展示兼容性
                    if (".jpg.JPG".contains(suffix)) {
                        suffix = "jpeg";
                    }
                    resourceModel.setMimeType(IMAGE_SUFFIX.concat(suffix));
                } else {
                    resourceModel.setMimeType(MIMETYPE_SUFFIX.concat(suffix));
                }

                redisTemplate.boundHashOps(KEY_WORKFLOW_ATTACHMENT).putIfAbsent(refId, resourceModel);
                redisTemplate.expire(KEY_WORKFLOW_ATTACHMENT, 24, TimeUnit.HOURS);
                if (isRichText != null && isRichText) {
                    getBizObjectFacade().batchInsertAttachments(Collections.singletonList(resourceModel));
                }
                return getOkResponseResult(resourceModel, "文件上传成功");
            }
        } catch (IOException e) {
            log.warn(e.getMessage(), e);
            throw new PortalException(
                    ResultEnum.OSS_UPLOAD_ERR.getErrCode(), ResultEnum.OSS_UPLOAD_ERR.getErrMsg());
        }
        throw new PortalException(
                ResultEnum.OSS_UPLOAD_ERR.getErrCode(), ResultEnum.OSS_UPLOAD_ERR.getErrMsg());
    }

    public void checkFileType(String fileName) throws PortalException {
        String suffix = fileName.substring(fileName.lastIndexOf('.'));
        if (StringUtils.isEmpty(suffix)) {
            throw new PortalException(ResultEnum.FILE_TYPE_ILLEGAL.getErrCode(), ResultEnum.FILE_TYPE_ILLEGAL.getErrMsg());
        }
        //白名单包含后缀名
        boolean contain = FILE_TYPE_WHITE_LIST.contains(suffix) || FILE_TYPE_WHITE_LIST.contains(suffix.toLowerCase()) || FILE_TYPE_WHITE_LIST.contains(suffix.toUpperCase());
        if (!contain) {
            throw new PortalException(ResultEnum.FILE_TYPE_ILLEGAL.getErrCode(), ResultEnum.FILE_TYPE_ILLEGAL.getErrMsg());
        }
        //文件名包含黑名单
        for (String illegal : IGNORE_FILE_TYPES) {
            boolean containsIllegal = fileName.contains(illegal) || fileName.contains(illegal.toLowerCase()) || fileName.contains(illegal.toUpperCase());
            if (containsIllegal) {
                throw new PortalException(ResultEnum.FILE_TYPE_ILLEGAL.getErrCode(), ResultEnum.FILE_TYPE_ILLEGAL.getErrMsg());
            }
        }
    }

    /**
     * 检查上传的文件是否图片
     *
     * @param file 上传的文件
     * @return Boolean
     */
    private Boolean checkImageFile(MultipartFile file) {
        try {
            // 根据图片内容判断是否为图片文件
            InputStream inputStream = file.getInputStream();
            BufferedImage bi = ImageIO.read(inputStream);
            if (bi != null) {
                return Boolean.TRUE;
            }
        } catch (Exception e) {
            log.debug("检查图片时异常: {}", e.getMessage(), e);
            return Boolean.FALSE;
        }
        return Boolean.FALSE;
    }

    @GetMapping(value = "/download")
    @ResponseBody
    @ApiOperation(value = "oss 文件下载接口")
    @ApiImplicitParam(
            name = "refId",
            value = "资源id",
            required = true,
            dataType = "String",
            paramType = "query")
    public void download(@RequestParam String refId, HttpServletResponse response) {
        validateNotEmpty(refId, "refId 不能为空");
        if (refId.contains(".") && FileStorageConfiguration.getFileUploadType() == FileUploadType.FTP) {
            response.setCharacterEncoding(Charsets.UTF_8.name());
            String suffix = refId.substring(refId.lastIndexOf('.') + 1);
            if (PIC_EXTENSION.contains(suffix)) {
                //IE图片展示兼容性
                if (".jpg.JPG".contains(suffix)) {
                    suffix = "jpeg";
                }
                response.setContentType(IMAGE_SUFFIX.concat(suffix));
            } else {
                response.setContentType(MIMETYPE_SUFFIX.concat(refId.substring(refId.lastIndexOf('.') + 1)));
            }
            try {
                //判断是否是IE11
                String header = getRequest().getHeader("User-Agent").toUpperCase();
                Boolean flag = header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE");
                if (flag) {
                    response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(refId, "UTF-8"));
                } else {
                    response.setHeader("Content-Disposition", "attachment; filename=" + new String(refId.getBytes("utf-8"), "ISO8859-1"));
                }
                sftpClient.downloadFile(refId, response);
            } catch (Exception e) {
                log.warn(e.getMessage(), e);
            }
            return;
        }
        AttachmentModel resourceModel = getBizObjectFacade().getAttachmentByRefId(refId);
        if (resourceModel == null) {
            Object object = redisTemplate.boundHashOps(KEY_WORKFLOW_ATTACHMENT).get(refId);
            resourceModel = (AttachmentModel) object;
        }
        if (resourceModel == null) {
            throw new PortalException(
                    ResultEnum.OSS_DOWNLOAD_PERMISSION_ERR.getErrCode(),
                    ResultEnum.OSS_DOWNLOAD_PERMISSION_ERR.getErrMsg());
        }
        if (FileStorageConfiguration.getFileUploadType() == FileUploadType.OSS) {
            log.debug("the download type is sso");
            OSS client = null;
            try {

                String ossKey = resourceModel.getRefId();
                OssConfigVO ossConfig = ossClient.getOssConfig();
                client = ossClient.getClient(ossConfig);
                OSSObject ossObject = client.getObject(ossConfig.getBucket(), ossKey);
                if (ossObject == null) {
                    throw new PortalException(ResultEnum.OSS_UPLOAD_ERR.getErrCode(), "OSS 文件不存在：refId=".concat(ossKey));
                }
                InputStream inputStream = ossObject.getObjectContent();
                response.setCharacterEncoding(Charsets.UTF_8.name());
                response.setContentType(resourceModel.getMimeType());
                response.setHeader(
                        "Content-Disposition",
                        "attachment; fileName=" + URLEncoder.encode(resourceModel.getName(), "UTF-8"));
                //response.getOutputStream().write(IOUtils.toByteArray(inputStream));
                IOUtils.copy(inputStream, response.getOutputStream());
            } catch (IOException e) {
                log.warn("文件下载失败: {}", e.getMessage(), e);
                throw new PortalException(ResultEnum.OSS_UPLOAD_ERR.getErrCode(), ResultEnum.OSS_UPLOAD_ERR.getErrMsg());
            } finally {
                if (client != null) {
                    client.shutdown();
                }
            }
        } else {
            log.debug("the download type is sftp");
            String fileName = resourceModel.getRefId().concat(resourceModel.getName());
            response.setCharacterEncoding(Charsets.UTF_8.name());
            response.setContentType(resourceModel.getMimeType());
            try {
                String header = getRequest().getHeader("User-Agent").toUpperCase();
                Boolean flag = header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE");
                if (flag) {
                    response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(resourceModel.getName(), "UTF-8"));
                } else {
                    response.setHeader("Content-Disposition", "attachment; filename=" + new String(resourceModel.getName().getBytes("utf-8"), "ISO8859-1"));
                }
                sftpClient.downloadFile(fileName, response);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    public void downloadPicture(String fileName, String dirPath, String refid) {
        validateNotEmpty(fileName, "refId 不能为空");
        if (fileName.contains(".") && FileStorageConfiguration.getFileUploadType() == FileUploadType.FTP) {

            try {
                sftpClient.downloadFileToDir(fileName, dirPath);
            } catch (Exception e) {
                log.warn(e.getMessage(), e);
            }
            return;
        }

        if (FileStorageConfiguration.getFileUploadType() == FileUploadType.OSS) {
            OSS client = null;
            try {
                String ossKey = refid;
                OssConfigVO ossConfig = ossClient.getOssConfig();
                client = ossClient.getClient(ossConfig);
                OSSObject ossObject = client.getObject(ossConfig.getBucket(), ossKey);
                if (ossObject == null) {
                    throw new PortalException(ResultEnum.OSS_UPLOAD_ERR.getErrCode(), "OSS 文件不存在：refId=".concat(ossKey));
                }
                InputStream inputStream = ossObject.getObjectContent();
                FileOutputStream fos = new FileOutputStream(new File(dirPath + File.separator + fileName));
                int i = -1;
                while ((i = inputStream.read()) != -1) {
                    fos.write(i);
                }
                fos.close();
            } catch (IOException e) {
                log.error("文件下载失败: {}", e.getMessage(), e);
                throw new PortalException(ResultEnum.OSS_UPLOAD_ERR.getErrCode(), ResultEnum.OSS_UPLOAD_ERR.getErrMsg());
            } finally {
                if (client != null) {
                    client.shutdown();
                }
            }
        }

    }

    @GetMapping(value = "/download_multi")
    @ResponseBody
    @ApiOperation(value = "oss 文件批量下载接口")
    public void multiDownload(
            String multiVO, HttpServletRequest request, HttpServletResponse response) {
        if (StringUtils.isEmpty(multiVO)) {
            throw new PortalException(ResultEnum.OSS_DOWNLOAD_ERR.getErrCode(), ResultEnum.OSS_DOWNLOAD_ERR.getErrMsg());
        }
        List<String> refIds = Arrays.asList(multiVO.split(","));
        String userId = getUserId();
        if (Strings.isNullOrEmpty(userId)) {
            throw new PortalException(ResultEnum.GET_USERINFO_ERR.getErrCode(), ResultEnum.GET_USERINFO_ERR.getErrMsg());
        }

        OSS client = null;
        String zipSuffix = ".zip";
        BufferedOutputStream out = null;
        BufferedInputStream buff = null;
        FileInputStream fis = null;
        File zipFile = null;
        ChannelSftp sftp = null;
        try {
            String prefix = UUID.randomUUID().toString();
            String zipFileName = prefix.concat(zipSuffix);
            // 创建临时文件
            zipFile = File.createTempFile(prefix, zipSuffix);
            FileOutputStream f = new FileOutputStream(zipFile);
            CheckedOutputStream csum = new CheckedOutputStream(f, new Adler32());
            // 用于将数据压缩成Zip文件格式
            ZipOutputStream zos = new ZipOutputStream(csum);
            // 校验权限
            Map<String, AttachmentModel> attachmentModelMap = Maps.newHashMap();
            List<String> fileNames = new ArrayList<>();
            for (String refId : refIds) {
                AttachmentModel resourceModel = null;
                Object object = redisTemplate.boundHashOps(KEY_WORKFLOW_ATTACHMENT).get(refId);
                resourceModel = object == null ? null : (AttachmentModel) object;
                if (resourceModel == null) {
                    resourceModel = getBizObjectFacade().getAttachmentByRefId(refId);
                }
                if (resourceModel == null) {
                    throw new PortalException(
                            ResultEnum.OSS_DOWNLOAD_PERMISSION_ERR.getErrCode(),
                            ResultEnum.OSS_DOWNLOAD_PERMISSION_ERR.getErrMsg());
                }
                attachmentModelMap.put(refId, resourceModel);
            }
            //int count = 0;
            if (FileStorageConfiguration.getFileUploadType() == FileUploadType.FTP) {
                sftp = sftpClient.createSftp();
            } else {
                OssConfigVO ossConfig = ossClient.getOssConfig();
                client = ossClient.getClient(ossConfig);
            }
            for (String refId : refIds) {
                InputStream inputStream = null;
                AttachmentModel attachmentModel = attachmentModelMap.get(refId);

                if (FileStorageConfiguration.getFileUploadType() == FileUploadType.OSS) {
                    OssConfigVO ossConfig = ossClient.getOssConfig();
                    OSSObject ossObject = client.getObject(ossConfig.getBucket(), refId);
                    if (ossObject == null) {
                        throw new PortalException(
                                ResultEnum.OSS_UPLOAD_ERR.getErrCode(), "OSS 文件不存在：refId=".concat(refId));
                    }
                    log.debug("the batch download type is oss");
                    inputStream = ossObject.getObjectContent();
                } else {
                    log.debug("the batch download type is sftp");
                    //count ++;
                    String fileName = refId.concat(attachmentModel.getName());
                    try {
                        inputStream = sftp.get(sftpClient.getFileName(fileName));
                    } catch (SftpException e) {
                        log.error(e.getMessage(), e);
                    }

                    /*if (count == refIds.size()) {
                        inputStream = sftpClient.getInputStream(fileName,true);
                    } else {
                        inputStream = sftpClient.getInputStream(fileName,true);
                    }*/
                }
                //处理可能重复的文件名
                parseFileNames(fileNames, attachmentModel);
                // 对于每一个要被存放到压缩包的文件，都必须调用ZipOutputStream对象的putNextEntry()方法，确保压缩包里面文件不同名

                zos.putNextEntry(new ZipEntry(attachmentModel.getName()));
                // 支持中文
                int bytesRead;
                // 向压缩文件中输出数据
                if (inputStream != null) {
                    while ((bytesRead = inputStream.read()) != -1) {
                        zos.write(bytesRead);
                    }
                    inputStream.close();
                }
                zos.closeEntry(); // 当前文件写完，定位为写入下一条项目
            }
//            if (FileStorageConfiguration.getFileUploadType() == FileUploadType.FTP) {
//                sftpClient.disconnect(sftp);
//            }

            zos.close();
            String header = request.getHeader("User-Agent").toUpperCase();
            zipFileName = getDisposition(zipFileName);
//            if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) {
//                zipFileName = URLEncoder.encode(zipFileName, "utf-8");
//                // IE下载文件名空格变+号问题
//                zipFileName = zipFileName.replace("+", "%20");
//            } else {
//                zipFileName = new String(zipFileName.getBytes(), "ISO8859-1");
//            }
            response.reset();
            response.setContentType("text/plain");
            response.setContentType("application/octet-stream; charset=utf-8");
            response.setHeader("Location", zipFileName);
            response.setHeader("Cache-Control", "max-age=0");
            response.setHeader("Content-Disposition", "attachment; filename=".concat(zipFileName));

            fis = new FileInputStream(zipFile);
            buff = new BufferedInputStream(fis);
            out = new BufferedOutputStream(response.getOutputStream());
            byte[] car = new byte[1024];
            int length = 0;
            while (length < zipFile.length()) {
                int j = buff.read(car, 0, 1024);
                length += j;
                out.write(car, 0, j);
            }

            // 删除临时文件
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new PortalException(ResultEnum.OSS_DOWNLOAD_ERR.getErrCode(), ResultEnum.OSS_DOWNLOAD_ERR.getErrMsg());
        } finally {
            try {
                if (sftp != null) {
                    sftpClient.disconnect(sftp);
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            if (zipFile != null) {
                zipFile.delete();
            }
            // 关闭流
            try {
                if (fis != null) {
                    fis.close();
                }
                if (buff != null) {
                    buff.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                log.error(e.getMessage());
            }
            if (client != null) {
                client.shutdown();
            }
        }
        //return getOkResponseResult("批量下载失败");
    }


    /**
     * 解决Firefox Safari浏览器文件乱码问题
     *
     * @param fileName 文件名
     * @return Content-Disposition Value
     */
    public String getDisposition(String fileName) {
        String headerValue = "attachment;";
        headerValue += " filename=\"" + encodeURIComponent(fileName) + "\";";
        headerValue += " filename*=utf-8''" + encodeURIComponent(fileName);
        return headerValue;
    }

//    public String getDispositions(String fileName) {
//        String headerValue = "attachment;";
//        headerValue += " filename=\"" + fileName + "\";";
//        headerValue += " filename*=utf-8''" + fileName;
//        return headerValue;
//    }


    /**
     * URLEncoder
     *
     * @param value 参数
     * @return url
     */
    public String encodeURIComponent(String value) {
        try {
            return URLEncoder.encode(value, StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20");
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

    private void parseFileNames(List<String> fileNames, AttachmentModel resourceModel) {
        String fileName = null;
        String[] fileInfo = getFileInfo(resourceModel.getName());
        String toPrefix = fileInfo[0];
        String toSuffix = fileInfo[1];
        int i = 1;
        while (true) {
            if (fileNames.contains(resourceModel.getName())) {
                if(log.isDebugEnabled()) {
                    log.debug("文件名为{}", resourceModel.getName());
                }
                fileName = toPrefix + "(" + i + ")" + toSuffix;
                resourceModel.setName(fileName);
                i++;
            } else {
                fileNames.add(resourceModel.getName());
                break;
            }
        }
    }

    @PostMapping(value = "/uploadImageForDingtalk")
    @ResponseBody
    @ApiOperation(value = "oss 文件上传接口,注意：key 用 file")
    public ResponseResult<AttachmentModel> uploadImageForDingtalk(String url, Boolean isAddWatermark, String locationInfo) throws Exception {
        String fileExtention = ImageUtil.getFileExtention(url);
        if(log.isDebugEnabled()) {
            log.debug("url:{}", url);
            log.debug("fileExtention：{}", fileExtention);
        }
        String fileName = "temp" + System.currentTimeMillis() + "." + fileExtention;
        //检查上传文件类型
        checkFileType(fileName);
        String fileNameTemplate = null;
        String suffix = fileName.substring(fileName.lastIndexOf('.') + 1);
        String refId = UUID.randomUUID().toString().replace("-", "");

        fileNameTemplate = refId.concat(fileName);
        byte[] bytes = new byte[0];
        bytes = ImageUtil.getBypes(url, bytes);

        if (log.isDebugEnabled()) {
            log.debug("fileName:{},refId:{}", fileName, refId);
            log.debug("size:{}", bytes.length);
            log.debug(" isAddWatermark = {}, locationInfo = {}", isAddWatermark, locationInfo);
        }
        //执行添加水印操作
        if (isAddWatermark != null && isAddWatermark) {
            int orientation = 0;
            try {
                Metadata metadata = ImageMetadataReader.readMetadata(new ByteArrayInputStream(bytes));
                Directory directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
                if (directory != null && directory.containsTag(ExifDirectoryBase.TAG_ORIENTATION)) {
                    orientation = directory.getInt(ExifDirectoryBase.TAG_ORIENTATION);
                    log.debug("图片方向为:{}", orientation);
                }
            } catch (Exception e) {
                //do nothing
            }

            // 如果是图片，则根据配置加上水印
            String userId = getUserId();
            UserModel user = getOrganizationFacade().getUser(userId);
            String userName = (user == null ? "" : user.getName());
            LocalDateTime now = LocalDateTime.now();
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            if (StringUtils.isNotEmpty(locationInfo) && locationInfo.length() > 40) {
                // 支持最多40个字，超过的…表示
                locationInfo = locationInfo.substring(0, 40) + "...";
            }
            FontTextVO fontTextVO = new FontTextVO(Lists.newArrayList(now.format(dateTimeFormatter) + " " + userName, locationInfo), 9, "#FFFFFF", 24, "SimHei", 0d, 0.64f);
            bytes = ImageUtils.drawTextInImg(bytes, fontTextVO, orientation);
            if (log.isDebugEnabled()) {
                log.debug("drawTextInImg is finished....");
            }
        }

        log.debug("<----------转换图片开始---------->");
        BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes));
        log.debug("<----------转换图片结束---------->");
        log.debug("<----------压缩图片开始---------->");
        BufferedImage smallImage = ImageUtil.resizeImage(image, 5);
        String smallimageBase64 = ImageUtil.imageThumbnailsToBase64(smallImage, fileName);
        log.debug("<----------压缩图片结束---------->");

        if (FileStorageConfiguration.getFileUploadType() == FileUploadType.OSS) {
            log.debug("the upload type is sso");
            File outputfile = new File(fileNameTemplate);
            FileOutputStream os = FileUtils.openOutputStream(outputfile);
            os.write(bytes);
            // 上传到OSS
            ossClient.fileUpload(refId, outputfile);
            outputfile.delete();

        } else {
            log.debug("the upload type is sftp");
            try {
                sftpClient.uploadFile(fileNameTemplate, new ByteArrayInputStream(bytes));
            } catch (Exception e) {
                log.error("", e);
                throw e;
            }
        }

        // {"refId":"xxx","name":"filename","fileSize":10000,"fileExtension":".pdf","mimeType":"application/pdf","storageMethod":"oss"}
        AttachmentModel resourceModel = new AttachmentModel();
        resourceModel.setRefId(refId);
        resourceModel.setName(fileName);
        resourceModel.setFileSize(bytes.length);
        resourceModel.setFileExtension(".".concat(fileExtention));
        resourceModel.setRemarks(smallimageBase64);
        if (PIC_EXTENSION.contains(fileExtention)) {
            //IE图片展示兼容性
            if (".jpg.JPG".contains(fileExtention)) {
                suffix = "jpeg";
            }
            resourceModel.setMimeType(IMAGE_SUFFIX.concat(suffix));
        } else {
            resourceModel.setMimeType(MIMETYPE_SUFFIX.concat(suffix));
        }

        redisTemplate.boundHashOps(KEY_WORKFLOW_ATTACHMENT).putIfAbsent(refId, resourceModel);
        redisTemplate.expire(KEY_WORKFLOW_ATTACHMENT, 24, TimeUnit.HOURS);
        return getOkResponseResult(resourceModel, "文件处理成功");
    }


}
